/**
 * $Revision: 1.0 $
 * $Author: Eric Yang $
 * $Date: Aug 7, 2007 12:43:58 AM $
 *
 * Author: Eric Yang
 * Date  : Aug 7, 2007 12:43:58 AM
 *
 */
package com.gooex.service.organization.impl;

import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.c4j.string.StringTools;
import org.c4j.system.web.hibernate.BaseHibernateService;

import com.gooex.domain.organization.Area;
import com.gooex.domain.organization.Authority;
import com.gooex.domain.organization.AuthorizedObject;
import com.gooex.domain.organization.Group;
import com.gooex.domain.organization.Role;
import com.gooex.service.organization.AuthorityContext;
import com.gooex.service.organization.IAreaManager;
import com.gooex.service.organization.IAuthorityManager;
import com.gooex.service.organization.IGroupManager;
import com.gooex.service.organization.IRoleManager;
import com.gooex.service.organization.exception.AuthoritionException;

/**
 * @author Eric Yang
 * @version 1.0
 */
public class AuthorityManagerImpl extends BaseHibernateService implements IAuthorityManager {

	private static final Log logger = LogFactory.getLog(AuthorityManagerImpl.class);

	private IAreaManager areaManager;

	private IGroupManager groupManager;

	private IRoleManager roleManager;

	public Authority getAuthority(String id) {
		if (StringTools.isBlankOrNull(id))
			return null;
		return (Authority) getHibernateTemplate().get(Authority.class, id);
	}

	public List<Authority> getAuthorities() {
		return getHibernateTemplate().find("from Authority");
	}

	public Authority getAuthorityByName(String name) {
		String hql = "from " + Authority.class.getName() + " where name=?";
		List<Authority> authorities = getHibernateTemplate().find(hql, name);
		if (authorities != null && authorities.size() == 1)
			return authorities.get(0);
		return null;
	}

	public void saveAuthority(Authority authority) {
		if (StringTools.isBlankOrNull(authority.getId())) {
			authority.setId(null);
		}
		getHibernateTemplate().saveOrUpdate(authority);
	}

	public void removeAuthority(Authority authority) throws AuthoritionException {
		authority = getAuthority(authority.getId());
		if (AuthorityContext.getSystemAuthorities().contains(authority)) {
			throw new AuthoritionException("Can't remove system authority!");
		}
		try {
			getHibernateTemplate().delete(authority);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new AuthoritionException(e.getMessage());
		}
	}

	public void saveAuthorizedObject(AuthorizedObject authorizedObject) {
		if (authorizedObject instanceof Area)
			areaManager.saveArea((Area) authorizedObject);
		else if (authorizedObject instanceof Group)
			groupManager.saveGroup((Group) authorizedObject);
		else if (authorizedObject instanceof Role)
			roleManager.saveRole((Role) authorizedObject);
	}

	public boolean authorize(AuthorizedObject target, AuthorizedObject grantor, Authority authority) {
		if (!grantor.isGrantor()) {
			logger.error(grantor.getName() + " has no right to grant authority!");
			return false;
		}
		if (!hasAuthority(grantor, authority)) {
			logger.error(grantor.getName() + " has no authority[" + authority.getName() + "]!");
			return false;
		}
		if (target.getAuthorities().contains(authority)) {
			logger.error("Duplicated authorized!");
			return false;
		}

		target.getAuthorities().add(authority);
		saveAuthorizedObject(target);
		return true;
	}

	public boolean isSystemAuthority(Authority authority) {
		Set<Authority> systemAuthorities = AuthorityContext.getSystemAuthorities();
		for (Authority auth : systemAuthorities) {
			if (auth.equals(authority))
				return true;
		}
		return false;
	}

	public boolean isSystemAuthorizedObject(AuthorizedObject obj) {
		Set<AuthorizedObject> objects = AuthorityContext.getSystemAuthorizedObjects();
		for (Iterator<AuthorizedObject> iterator = objects.iterator(); iterator.hasNext();) {
			AuthorizedObject item = iterator.next();
			if (item.equals(obj))
				return true;
		}
		return false;
	}

	public boolean hasAuthority(AuthorizedObject authorizedObject, Authority authority) {
		if (authorizedObject instanceof Area) {
			if (AuthorityContext.getSuperArea().equals(authorizedObject))
				return true;
		} else if (authorizedObject instanceof Group) {
			if (AuthorityContext.getSuperGroup().equals(authorizedObject))
				return true;
		} else if (authorizedObject instanceof Role) {
			if (AuthorityContext.getSuperRole().equals(authorizedObject))
				return true;
		}
		return authorizedObject.getAuthorities().contains(authority);
	}

	public void setRoleManager(IRoleManager roleManager) {
		this.roleManager = roleManager;
	}

	public void setAreaManager(IAreaManager areaManager) {
		this.areaManager = areaManager;
	}

	public void setGroupManager(IGroupManager groupManager) {
		this.groupManager = groupManager;
	}

}
